CHAT 💬 X.509 Swift Console

Сектор клієнтської розробки SYNRC CHAT відкриває серію статей присвячених розробці на Swift. Якшо коротко то спочатку ми будемо вчитися працювати з бінарними форматами ASN.1 DER використовуючи бібліотеки Apple. А потім напишемо ASN.1 компілятор з кодогенерацією в Swift 5.8 по ASN.1 специфікаціям які входять до складу SYNRC CA, ключового криптографічного компоненту та головної залежності SYNRC CHAT.

Для початку ми бачимо клієнт CHAT X.509 як read-eval-print цикл як такий, що можна побачити в самому Swift, Elixir та майже кожній сучасній мові програмування. Поки що питання текстового протоколу оператора консолі залищається відкритим, одна уже можна задекларувати принципи на яких буде побудована UTF-8 консоль: перший — це termio інтерфейс і другий — це своя мова і протокол спілкування виконаний у вигляді REPL.

Створення проєкту

Покажемо необхідний мінімум для створення проєету. По-перше треба зробити файл проекту Package.swift. Зверніть увагу на версію Swift в коментарі першого рядка. Всі таргети повинні відповідати папкам та зазвичай знаходяться в папці Sources. Цей додаток використовує тільки дві залежності swift-asn1 і swift-crypto, всі реалізації обгорток в swift-certificates я переніс в папку CMS. Зверніть увагу що там вони використвують внутрішній таргет _CryptoExtras з залежності swift-crypto. Також хочеться додати шо можна було би не красти файли з swift-certificates, а просто поставити її в залежність тоді треба було би робити @testable import X509, але чомусь це забороняє створювати релізи swift build -c release. Не тільки це стало причиною переносу файлів з swift-certificates — оскільки ми хочемо аби всі обгортки X509 які зараз лежать в swift-certificates в майбутньому були замінені на результати роботи SYNRC ASN.1 компілятора, ми навмисно не включаємо бібіліотеку в залежності аби поступово замінювати файли що там знаходяться на згенеровані сумісні версії.

// swift-tools-version: 5.8 import PackageDescription import class Foundation.ProcessInfo let package = Package( name: "chat-x509", platforms: [ .macOS(.v10_15), .iOS(.v13) ], products: [ .executable(name: "chat-x509", targets: ["SwiftConsole"]), ], targets: [ .executableTarget( name: "SwiftConsole", dependencies: [ .product(name: "Crypto", package: "swift-crypto"), .product(name: "_CryptoExtras", package: "swift-crypto"), .product(name: "SwiftASN1", package: "swift-asn1"), ]), ] ) if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil { package.dependencies += [ .package(url: "https://github.com/apple/swift-crypto.git", from: "2.6.0"), .package(url: "https://github.com/apple/swift-asn1.git", from: "0.8.0"), ] }

REPL

Наступним кроком підготуємо головну програму яка компілюється в бінарний файл chat-x509 на всіх платформах: Windows, Linux, Mac.

import SwiftASN1 import Crypto import Foundation func exists(f: String) -> Bool { return FileManager.default.fileExists(atPath: f) } func run() throws { print(": CHAT 💬 X.509 © SYNRC") print("> ", terminator: "") while let line = readLine() { let data = line.components(separatedBy: " ") if (data.joined() == "") { print("> ", terminator: "") continue } else { let args = data.filter { $0 != "" } print(": \(args)") } if (data.count > 2 && data[0] == "show") { switch (data[2]) { case "crt": try showCRT(name: data[1]) case "csr": try showCSR(name: data[1]) case "cms": try showCMS(name: data[1]) default: () } } print("> ", terminator: "") } print("Bye!") } try run()

Підтримка DER пакетів

Покажемо на прикладі як використовувати X509 обгортки з Apple бібліотеки swift-certificates, для цього в репозиторії закомічено 3 файли: cms.bin (CMS), ca.crt (CRT), ec_sha256.der (CSR). Для відображення розпарсаної інформації з цих файлів в клієнті використовується наприклад наступна команда: show ca.crt crt, де другий параметр show crt показує тип структури, а перший — ім'я файла де знаходиться структура.

func showCMS(name: String) throws { print(": CMS=\(name)") let url = URL(fileURLWithPath: name) if (!exists(f: url.path)) { print(": CMS file not found.") } else { let data = try Data(contentsOf: url) let cms = try CMSContentInfo(derEncoded: Array(data)) print(": \(cms.contentType)") } } func showCRT(name: String) throws { print(": CRT=\(name)") let url = URL(fileURLWithPath: name) if (!exists(f: url.path)) { print(": CRT file not found.") } else { let data = try Data(contentsOf: url) let crt = try Certificate(derEncoded: Array(data)) print(": \(crt)") } } func showCSR(name: String) throws { print(": CSR=\(name)") let url = URL(fileURLWithPath: name) if (!exists(f: url.path)) { print(": CSR file not found.") } else { let data = try Data(contentsOf: url) let csr = try CertificateSigningRequest(derEncoded: Array(data)) print(": \(csr)") } }

Запуск та компіляція клієнта

Для компіляції релізу зазвичай використовується:

$ swift build -c release

А для запуску зі swift:

$ rlwrap swift run Building for debugging... Build complete! (0.65s) : CHAT 💬 X.509 © SYNRC > > show ec_sha256.der csr : ["show", "ec_sha256.der", "csr"] : CSR=ec_sha256.der : CertificateSigningRequest(version: CSRv1, subject: L=Austin, ST=Texas,C=US,O=PyCA,CN=cryptography.io, publicKey: P384, attr ibutes: Attributes([]), signatureAlgorithm: SignatureAlgorithm .ecdsaWithSHA256, signature: ECDSA > > show cms.bin cms : ["show", "cms.bin", "cms"] : CMS=cms.bin : 1.2.840.113549.1.7.3 > > show ca.crt crt : ["show", "ca.crt", "crt"] : CRT=ca.crt : Certificate(version: X509v3, serialNumber: 31:a2:d0:1d:78:3c :8:71:52:f8:51:71:43:ab:1a:bc:fa:a2:86:97, issuer: "CN=CA,O=SY NRC,ST=Kyiv,C=UA", subject: "CN=CA,O=SYNRC,ST=Kyiv,C=UA", notV alidBefore: 2023-06-14 06:34:49 +0000, notValidAfter: 2033-06- 11 06:34:49 +0000, publicKey: P384, signature: ECDSA, extensio ns: [SubjectKeyIdentifier(97:21:88:41:9c:a5:ce:53:89:bd:11:64: ee:5d:da:b4:af:de:8d:db), AuthorityKeyIdentifier(keyID: 97:21: 88:41:9c:a5:ce:53:89:bd:11:64:ee:5d:da:b4:af:de:8d:db), BasicC onstraints(CA=TRUE), KeyUsage(digitalSignature, keyCertSign, c RLSign)]) > > >

Репозиторій проєкту — chat-x509/swift-console.


˙


˙

[1]. ITU-T ASN.1 Compilers
[2]. Apple Swift ASN.1 Library Documentation.
[3]. Let's Encrypt. Ласкаво просимо в ASN.1 і DER
[4]. Swift Crypto Library Documentation
[5]. Swift Certificates Library Documentation
[6]. Olivier Dubuisson. ASN.1 Communication between Heterogeneous Systems
[7]. 2023-08-07 CHAT ASN.1
[8]. 2023-08-08 ASN.1 Компілятор